package com.codeduck.validate.handler;

import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Path;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * 参数校验全局异常处理
 *
 * @author: <a href="mailto:codeduck@163.com">Codeduck</a>
 * @createDate: 2021-12-26
 */
@RestControllerAdvice
@Slf4j
public class ValidateExceptionHandler {

    @ExceptionHandler({BindException.class, ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
    public Map<String,String> validateExceptionHandler(Exception exception) {
        Map<String, String> res = new HashMap<>();
        if (exception instanceof ConstraintViolationException) {
            Set<ConstraintViolation<?>> constraintViolations = ((ConstraintViolationException) exception).getConstraintViolations();
            Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
            while (iterator.hasNext()) {
                ConstraintViolation<?> constraintViolation = iterator.next();
                PathImpl path = (PathImpl)constraintViolation.getPropertyPath();
                Iterator<Path.Node> pathIter = path.iterator();
                while (pathIter.hasNext()) {
                    Path.Node node = pathIter.next();
                    if (!pathIter.hasNext()) {
                        res.put(node.getName(), constraintViolation.getMessageTemplate());
                    }
                }
            }
        }
        if(exception instanceof BindException){
            BindingResult bindingResult = ((BindException)exception).getBindingResult();
            for(int i = 0; i < bindingResult.getFieldErrors().size(); i++){
                FieldError fieldError = bindingResult.getFieldErrors().get(i);
                res.put(fieldError.getField(), fieldError.getDefaultMessage());
            }
        }
        StringBuilder logInfo = new StringBuilder();
        if (!res.isEmpty()) {
            res.forEach((k, v) -> logInfo.append(k).append(": ").append(v).append(";"));
        }
        log.error("exception info : [{}]", logInfo);
        return  res;
    }
}
